package com.dhcc.bpm.modules.api.controller;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dhcc.bpm.common.annotation.Log;
import com.dhcc.bpm.common.constant.FilePathConstant;
import com.dhcc.bpm.common.enums.BusinessType;
import com.dhcc.bpm.common.json.JSONObject;
import com.dhcc.bpm.common.utils.FormatUtils;
import com.dhcc.bpm.common.utils.excel.ExcelUtils;
import com.dhcc.bpm.modules.api.entity.BaseProduct;
import com.dhcc.bpm.modules.api.entity.Product;
import com.dhcc.bpm.modules.api.entity.Sys;
import com.dhcc.bpm.modules.api.service.IApiService;
import com.dhcc.bpm.modules.api.service.IBaseProductService;
import com.dhcc.bpm.modules.api.service.IProductService;
import com.dhcc.bpm.modules.api.service.ISysService;
import com.dhcc.bpm.modules.api.vo.SysVO;
import com.dhcc.bpm.modules.common.entity.Plupload;
import com.dhcc.bpm.modules.common.entity.Upload;
import com.dhcc.bpm.modules.common.service.IPluploadService;
import com.dhcc.bpm.modules.gateway.service.IGatewayRouteService;
import com.dhcc.bpm.modules.log.service.IGatewayLogDayService;
import com.dhcc.bpm.modules.log.vo.AppApiViewVo;
import com.dhcc.bpm.modules.log.vo.ProductRankVo;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.google.common.collect.Lists;
import com.xkcoding.http.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @ClassName SysController
 * @Description 系统表 控制器
 * @Author daina
 * @Date 2020/2/25 13:14
 * @Version V1.0
 * @Copyright: 2020 东华软件 . All rights reserved.
 */
@RestController
@AllArgsConstructor
@NoArgsConstructor
@RequestMapping("bpm-api/sys")
@Api(value = "系统表", tags = "系统表接口")
public class SysController extends BladeController {
    private static final Logger log = LoggerFactory.getLogger(SysController.class);
    @Autowired
    private ISysService sysService;
    @Autowired
    private IProductService productService;
    @Autowired
    private IBaseProductService baseProductService;
    @Autowired
    private IGatewayRouteService gatewayRouteService;
    @Autowired
    private IApiService apiService;
    @Autowired
    private IGatewayLogDayService gatewayLogDayService;
    @Autowired
    private IPluploadService pluploadService;
    private String path;

    @Value("${bpm.file-public-path}")
    public void setFileUploadPath(String publicPath) {
        path = publicPath + FilePathConstant.SQLPATH;
    }

    private List<String> supportExcelType = Lists.newArrayList("xls", "xlsx");
    public static int processors = Runtime.getRuntime().availableProcessors();
    public static ThreadPoolExecutor executor = new ThreadPoolExecutor(processors * 5, processors * 10, 60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(processors * 20),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
    /**
     * @param sys
     * @return org.springblade.core.tool.api.R<com.dhcc.bpm.modules.api.entity.Sys>
     * @Description 详情
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "系统表详情", notes = "传入sys")
    @Log(title = "系统表详情", businessType = BusinessType.SELECT)
    @ApiLog("系统表详情")
    public R<Sys> detail(Sys sys) {
        Sys detail = sysService.getOne(Condition.getQueryWrapper(sys));
        return R.data(detail);
    }

    /**
     * @param sys
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.api.entity.Sys>>
     * @Description 分页 系统表
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入sys")
    @Log(title = "分页 系统表", businessType = BusinessType.SELECT)
    @ApiLog("分页 系统表")
    public R<IPage<SysVO>> list(SysVO sys, Query query, BladeUser bladeUser) {
        IPage<SysVO> pages = sysService.selectSysPage(Condition.getPage(query), sys);
        List<Future<SysVO>> futures = new ArrayList<>();
        List<SysVO> list = new ArrayList<>();
        if (sys.getIsFrom() != 1) {
            list = pages.getRecords().stream().map(sysVO -> {
                AppApiViewVo appApiViewVo = gatewayLogDayService.getCountBySysId(sysVO.getId());
                if (null == appApiViewVo) {
                    sysVO.setResponseTime(0.00);
                    sysVO.setNum(0L);
                    sysVO.setSuccessRate("0.00");
                    return sysVO;
                }
                sysVO.setResponseTime(appApiViewVo.getResponseTime());
                sysVO.setNum(appApiViewVo.getRequestNum());
                sysVO.setSuccessRate(Double.valueOf(appApiViewVo.getFailRate()) * 100 + "%");
                return sysVO;
            }).collect(Collectors.toList());
        } else {
            if (pages.getRecords() != null && pages.getRecords().size() > 0) {
                for (SysVO sysVO : pages.getRecords()) {
                    Future<SysVO> future = executor.submit(() -> {
                        // 求成功率
                        String successRateStr = "0.00";
                        // 平均响应时间
                        double avgResTime = 0.00;
                        Long num = 0L;
                        //sys对应的所有api
                        List<String> apiCodes = apiService.getApiBySysId(sysVO.getId());
                        // 统计信息  (响应次数、响应成功率、响应时间)
                        AppApiViewVo appApiViewVo = new AppApiViewVo();
                        appApiViewVo.setApiCodes(apiCodes);
                        if (StringUtil.isEmpty(sys.getEnv())) {
                            appApiViewVo.setEnv("0"); // 环境标志  0-生产环境
                        }
                        if (sys.getIsFrom() == 1) {
                            appApiViewVo.setBegDate(sys.getBegDate());
                            appApiViewVo.setEndDate(sys.getEndDate1());
                            appApiViewVo.setIsFrom(sys.getIsFrom());
                        }
                        AppApiViewVo apiCountData = gatewayLogDayService.apiCount(appApiViewVo);
                        if (apiCountData != null) {
                            DecimalFormat df = new DecimalFormat("0.00");//格式化小数

                            double successRate = 0.00;
                            if (apiCountData.getRequestNum() != 0) {
                                successRate = (double) apiCountData.getSuccessNum() / apiCountData.getRequestNum() * 100;

                                successRateStr = FormatUtils.doubleFormat(Double.valueOf(successRateStr) + successRate);
                            }


                            if (apiCountData.getLineNum() != 0) {
                                double temp = Double.valueOf(df.format(apiCountData.getResponseTime() / apiCountData.getLineNum()));
                                avgResTime = Double.valueOf(df.format(avgResTime + temp));
                            }
                            num += apiCountData.getRequestNum();
                        }
                        sysVO.setNum(num);
                        DecimalFormat df = new DecimalFormat("0.00");//格式化小数
                        if (successRateStr.equals("0.00") || apiCodes.size() == 0) {
                            sysVO.setSuccessRate("0.00%");
                        } else {
                            double SuccessRate = Double.valueOf(successRateStr) / apiCodes.size();
                            sysVO.setSuccessRate(Double.valueOf(df.format(SuccessRate)) + "%");
                        }

                        if (avgResTime == 0.0 || apiCodes.size() == 0) {
                            sysVO.setResponseTime(Double.valueOf(0.00));
                        } else {
                            sysVO.setResponseTime(Double.valueOf(df.format(avgResTime / apiCodes.size())));
                        }
                        return sysVO;
                    });
                    futures.add(future);
                }
            }
        }
        // 获取结果

        try {
            for (int i = 0 ; i < futures.size() ; i ++) {
                list.add(futures.get(i).get());
            }
        } catch (Exception e) {
            log.error("异常信息：", e);
        }
        pages.setRecords(list);
        return R.data(pages);
    }

    /**
     * @param sys
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.api.vo.SysVO>>
     * @Description 自定义分页 系统表
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @GetMapping("/page")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入sys")
    @Log(title = "自定义分页 系统表", businessType = BusinessType.SELECT)
    @ApiLog("自定义分页 系统表")
    public R<IPage<SysVO>> page(SysVO sys, Query query) {
        IPage<SysVO> pages = sysService.selectSysPage(Condition.getPage(query), sys);
        return R.data(pages);
    }

    /**
     * @param sys
     * @return org.springblade.core.tool.api.R
     * @Description 新增 系统表
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "新增", notes = "传入sys")
    @Log(title = "新增 系统表", businessType = BusinessType.INSERT)
    @ApiLog("新增 系统表")
    public R save(@Valid @RequestBody Sys sys) {
        return R.status(sysService.save(sys));
    }

    /**
     * @param sys
     * @return org.springblade.core.tool.api.R
     * @Description 修改 系统表
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入sys")
    @Log(title = "修改 系统表", businessType = BusinessType.UPDATE)
    @ApiLog("修改 系统表")
    public R update(@Valid @RequestBody Sys sys) {
        return R.status(sysService.updateById(sys));
    }

    /**
     * @param sys
     * @return org.springblade.core.tool.api.R
     * @Description 新增或修改 系统表
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @PostMapping("/submit")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改", notes = "传入sys")
    @Log(title = "新增或修改 系统表", businessType = BusinessType.INSERT)
    @ApiLog("新增或修改 系统表")
    @Transactional(rollbackFor = Exception.class)
    public R submit(@Valid @RequestBody Sys sys) {
        try {
            sysService.saveOrUpdate(sys);
            return R.data(sys);
        } catch (Exception e) {
            log.error("数据库异常：{}", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            if (e.getMessage().contains("for key 'sys_name_idx'") || e.getMessage().contains("ORA-00001")) {
                return R.fail(500, "该系统名已存在");
            }
            return R.fail(500, "数据库异常");
        } finally {

        }
    }


    /**
     * @param ids
     * @return org.springblade.core.tool.api.R
     * @Description 删除 系统表
     * @Author daina
     * @Date 14:39 2020/2/25
     **/
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "删除 系统表", notes = "传入ids")
    @Log(title = "删除 系统表", businessType = BusinessType.DELETE)
    @ApiLog("删除 系统表")
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        List<Long> list = Func.toLongList(ids);
        for (Long data : list) {
            List<BaseProduct> baseList = baseProductService.selectBySysId(data);
            List<Product> productList = productService.selectBySysId(data);
            if (baseList.size() > 0 || productList.size() > 0) {
                //说明该产品下有基础产品或应用产品
                return R.fail(267, "此产品下存在已有产品信息!");
            }
        }
        return R.status(sysService.deleteLogic(Func.toLongList(ids)));
    }

    /**
     * @param
     * @return com.dhcc.bpm.common.json.JSONObject
     * @Description 系统服务名关联查询
     * @Author daina
     * @Date 14:40 2020/2/25
     **/
    @GetMapping("/selectBySysName")
    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "查询所有系统名称", notes = "无参")
    @Log(title = "系统服务名关联查询", businessType = BusinessType.SELECT)
    @ApiLog("系统服务名关联查询")
    public JSONObject selectBySysName() {
        JSONObject object = new JSONObject();
        object.put("success", true);
        object.put("names", sysService.selectBySysName());
        return object;
    }


    /**
     * @param sysNum
     * @return java.util.List<com.dhcc.bpm.modules.api.vo.SysVO>
     * @throws
     * @Description 编码判断是否重复
     * @Author xiafayu
     * @Date 2020/3/21 20:18
     **/
    @ApiLog("查询系统编码")
    @PostMapping("/selectBySysNum")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "查询系统编码", notes = "sysNum")
    @Log(title = "查询系统编码", businessType = BusinessType.SELECT)
    public R selectBySysNum(@ApiParam(value = "系统编码", required = true) @RequestParam String sysNum) {
        List<SysVO> list = sysService.selectBySysNum(sysNum);
        if (list.size() > 0) {
            return R.data(false);
        }
        return R.data(true);
    }

    @PostMapping("/download")
    public void download(SysVO sys, HttpServletResponse response) {
        int page = 1;
        List<SysVO> sysVOList = new ArrayList<>();
        while (true) {
            Query query = new Query();
            query.setCurrent(page++);
            query.setSize(10);
            IPage<SysVO> pages = sysService.selectSysPage(Condition.getPage(query), sys);
            // 统计api 信息  (响应次数、响应成功率、响应时间)
            if (pages.getRecords() != null && pages.getRecords().size() > 0) {
                for (SysVO sysVO : pages.getRecords()) {
                    // 系统下产品集合
                    List<Product> sysProlist = productService.syslist(sysVO.getId().toString());

                    Long num = 0L, successNum = 0L, lneNum = 0L;
                    double avgResTime = 0.00;
                    String successRateStr = "0.00%";
                    if (sysProlist != null && sysProlist.size() > 0) {
                        // 产品统计
                        for (Product proVO : sysProlist) {
                            ProductRankVo productRankVo = new ProductRankVo();
                            productRankVo.setProductId(proVO.getId().toString());
                            productRankVo.setEnv("0"); // 环境标志  0-生产环境

                            List<ProductRankVo> rankList = gatewayLogDayService.countProductByDate(productRankVo);
                            if (rankList != null && rankList.size() > 0 && rankList.get(0) != null && rankList.get(0).getNum() != null) {
                                ProductRankVo rankVo = rankList.get(0);

                                num += rankVo.getNum();
                                successNum += rankVo.getSuccessNum();
                                lneNum += rankVo.getLineNum();
                                avgResTime += rankVo.getResponseTime();
                            }
                        }
                        //成功率
                        double successRate = 0;
                        DecimalFormat df = new DecimalFormat("0.00");//格式化小数
                        if (num != 0) {
                            successRate = (double) successNum / num * 100;//返回的是String类型
                            successRateStr = FormatUtils.doubleFormat(successRate) + "%";
                        }

                        // 平均响应时间
                        if (lneNum != 0) {
                            avgResTime = Double.valueOf(df.format(avgResTime / lneNum));
                        }
                    }
                    sysVO.setNum(num);
                    sysVO.setSuccessRate(successRateStr);
                    sysVO.setResponseTime(avgResTime);
                }
                sysVOList.addAll(pages.getRecords());
            } else {
                break;
            }
        }
//        ExcelUtil<SysVO> util = new ExcelUtil<SysVO>(SysVO.class);
//        util.exportExcel(sysVOList, "API系统管理信息表", response);
        ExcelUtils.exportExcel(sysVOList, "API系统管理信息表", "导出sheet1", Sys.class, "API系统管理信息表.xlsx", response);
    }

    @ApiLog("导入excel")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "导入excel", notes = "sysNum")
    @Log(title = "导入excel", businessType = BusinessType.SELECT)
    @PostMapping("importexcel")
    public R importexcel(Plupload plupload, HttpServletRequest request) {
//        String name = null;
        Upload upload = new Upload();
        upload.setRequest(request);
        Upload uploadEntity = pluploadService.getFile(upload);
        MultipartFile file = uploadEntity.getMultipartFile();
//        name = file.getOriginalFilename();
//        uploadEntity.setName(name);
//        //本地上传
//        String id = pluploadService.fileLocalUpload(plupload, upload, request).toString();
//        Plupload newupload = pluploadService.selectById(Long.parseLong(id));
//        try (InputStream inputStream = new FileInputStream(new File(path + "/"  + newupload.getFileRealname()))) {
//            ExcelUtil<Sys> excelUtil = new ExcelUtil<Sys>(Sys.class);
//            List<Sys> list = excelUtil.importExcel("API系统管理信息表", inputStream);
//            for (Sys sys : list) {
//                try {
//                    sysService.save(sys);
//                } catch (Exception e) {
//                    log.error("数据库异常：{}", e);
//                    if (e.getMessage().contains("for key 'sys_name_idx'") || e.getMessage().contains("ORA-00001")) {
//                        continue;
//                    } else {
//                        return R.fail(500, "数据库异常");
//                    }
//                } finally {
//
//                }
//            }
//            pluploadService.fileDelete(Long.parseLong(id));
//        } catch (FileNotFoundException e) {
//            log.error("异常信息:{}", e);
//        } catch (Exception e) {
//            log.error("异常信息:{}", e);
//        }
        ImportParams importParams = new ImportParams();
        // 数据处理
        //表格标题行数,默认0
        importParams.setHeadRows(1);
        //表头行数,默认1
        importParams.setTitleRows(1);
        //是否需要校验上传的Excel,默认false
//        importParams.setNeedVerify(false);
        ExcelImportResult<Sys> result = null;
        try {
            result = ExcelImportUtil.importExcelMore(file.getInputStream(), Sys.class, importParams);
            List<Sys> sysList = result.getList();
            if (sysList.size() > 0) {
                sysService.saveBatch(sysList);
            }
        } catch (Exception e) {
            log.error("导入数据失败;{}", e);
            return R.fail("导入失败");
        }
        List<Sys> failList = result.getFailList();
        StringBuilder failMsg = null;
        if (failList.size() < 1) {
            return R.success("导入成功");
        } else {
            failMsg = new StringBuilder();
            for (Sys sys : failList) {
                failMsg.append(sys.getSysName()).append(",");
            }
        }
        return R.success("名称为：[" + failMsg.substring(0, failMsg.length() - 1) + "]导入失败");
    }
}
